package simple.flow.config.shiro;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.stereotype.Component;
import simple.flow.common.RestResult;
import simple.flow.util.WebUtil;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义实现JWT过滤器，用于处理JWT认证和授权
 *
 * @author lhd
 * @since 2025/4/8 11:47
 */

@Slf4j
@Component
public class JwtFilter extends AccessControlFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        // 直接返回false让onAccessDenied处理
        return false;
    }

    protected boolean executeLogin(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader("Authorization");
        if (token == null) {
            log.error("请求未携带token，请求路径为：{}", httpServletRequest.getRequestURI());
            WebUtil.writeResponse(response, HttpServletResponse.SC_UNAUTHORIZED, RestResult.error("请求未携带token"));
            return false;
        }

        try {
            token = token.replace("Bearer ", "");
            // 提交给realm进行登入，如果错误他会抛出异常并被捕获
            getSubject(request, response).login(new JwtToken(token));
            return true;
        } catch (Exception e) {
            log.error("token校验失败，请求路径为：{}，错误信息：{}", httpServletRequest.getRequestURI(), e.getMessage());
            WebUtil.writeResponse(response, HttpServletResponse.SC_UNAUTHORIZED, RestResult.error("token无效或过期"));
            return false;
        }
    }

    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        // TODO 可以在这里进行一些跨域处理

        // 权限校验处理
        return super.onPreHandle(request, response, mappedValue);
    }

    @Override
    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) {
        // TODO 及时清理相关ThreadLocal，避免内存泄漏
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        return executeLogin(request, response);
    }

}
